﻿//========================================================= 
/**@file FileVirtualDevice.h
 * @brief 通过文件虚拟设备指令的设备
 * 
 * @date 2017-11-05   09:52:34
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_FILEVIRTUALDEVICE_H_
#define _LIBZHOUYB_FILEVIRTUALDEVICE_H_
//--------------------------------------------------------- 
#include "../../include/Base.h"
#include "../../include/BaseDevice.h"

#include "../../container/ini.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace extension {
namespace ability {
//--------------------------------------------------------- 
/**
 * @brief 文件中保存的指令数据结构
 * @date 2017-11-05 10:01:34
 */
struct CachedCmd
{
    ByteBuilder Name;
    ByteBuilder sCmd;
    ByteBuilder rCmd;
    uint DelayTime;
};
//--------------------------------------------------------- 
/**
 * @brief 缓存的命令集合
 * @date 2017-11-06 14:29
 */
class CachedCmdCollection : public IEnumerator<ReadOnlyEnumerator<CachedCmd> >
{
public:
    typedef ReadOnlyEnumerator<CachedCmd> EnumeratorType;
    typedef list_t<CachedCmd>::iterator Iterator;
protected:
    list_t<CachedCmd> _cachedCmds;
public:
    CachedCmdCollection() {}
    virtual EnumeratorType GetEnumerator() const
    {
        EnumeratorType enumer;
        typedef ListReadOnlyEnumerator<list_t<CachedCmd> > CollectionEnumeratorType;
        CollectionEnumeratorType* pNull = NULL;
        enumer.Create(_cachedCmds, pNull);
        return enumer;
    }
    inline Iterator Begin()
    {
        return _cachedCmds.begin();
    }
    inline Iterator End()
    {
        return _cachedCmds.end();
    }
    inline bool IsEof(Iterator itr) const
    {
        list_t<CachedCmd>::const_iterator constItr(itr);
        return constItr == _cachedCmds.end();
    }
    Iterator Get(const ByteArray& send)
    {
        for(Iterator itr = _cachedCmds.begin();itr != _cachedCmds.end(); ++itr)
        {
            if(itr->sCmd.IsEqual(send))
                return itr;
        }
        return _cachedCmds.end();
    }
    Iterator Put(const ByteArray& send, bool* pIsNew = NULL)
    {
        Iterator itr = Get(send);
        bool isNew = IsEof(itr);
        if(pIsNew != NULL)
        {
            (*pIsNew) = isNew;
        }
        if(isNew)
        {
            itr = _cachedCmds.push_back();
            itr->sCmd = send;
        }
        return itr;
    }
    inline size_t Count() const
    {
        return _cachedCmds.size();
    }
};
//--------------------------------------------------------- 
/**
 * @brief 设备通信指令录制器
 * @date 2017-11-05 23:50:15
 */
class CachedRecorder : 
    public IInteractiveTrans, 
    public BaseDevAdapterBehavior<IInteractiveTrans>,
    public RefObject
{
protected:
    CachedCmdCollection::Iterator _currItr;
    Timer _timer;
    bool _isNew;
public:
    CachedRecorder()
    {
        _currItr = Collection.Begin();
        _isNew = true;
    }
    CachedCmdCollection Collection;

    virtual bool Write(const ByteArray& data)
    {
        _currItr = Collection.Put(data, &_isNew);
        // 以最后一次操作的指令为准
        if(!_isNew)
        {
            _currItr->rCmd.Clear();
        }
        _timer.Restart();
        return _pDev->Write(data);
    }
    virtual bool Read(ByteBuilder& data)
    {
        size_t len = data.GetLength();
        if(!_pDev->Read(data))
            return false;
        if(!Collection.IsEof(_currItr))
        {
            ByteArray rBuff = data.SubArray(len);
            // 第一次接收数据时,设置发送数据和接收数据的时间间隔
            if(_currItr->rCmd.IsEmpty())
            {
                _currItr->DelayTime = static_cast<uint>(_timer.Elapsed());
            }
            _currItr->rCmd.Append(rBuff);
        }
        return true;
    }
};
//--------------------------------------------------------- 
/**
 * @brief 以文件虚拟设备的驱动
 * @date 2017-11-05 10:01:52
 */
class FileVirtualDevice : 
    public IBaseDevice, 
    public IInteractiveTrans, 
    public DeviceBehavior,
    public RefObject
{
public:
    /**
     * @brief 从文件中加载指令配置
     * @date 2017-11-06 10:50
     * 
     * @param [in] path 需要加载的文件路径
     * @param [out] collection 识别到的指令数据
     */
    static bool Load(const char* path, CachedCmdCollection& collection)
    {
        zhou_yb::container::IniFile ini;
        if(!ini.Open(path))
            return false;
        zhou_yb::container::IniFile::iterator itr;
        ByteBuilder data(32);
        for(itr = ini.begin();itr != ini.end(); ++itr)
        {
            zhou_yb::container::IniGroup::iterator subItr;
            CachedCmdCollection::Iterator cmdItr = collection.End();
            for(subItr = itr->begin();subItr != itr->end(); ++subItr)
            {
                ByteArray key(subItr->Key.c_str(), subItr->Key.length());
                if(StringConvert::Compare(key, "Send", true))
                {
                    data.Clear();
                    DevCommand::FromAscii(subItr->Value.c_str(), data);
                    bool isNew = false;
                    cmdItr = collection.Put(data, &isNew);

                    if(!isNew)
                    {
                        cmdItr = collection.End();
                    }
                    else
                    {
                        // 分组名称为命令描述
                        cmdItr->Name = itr->Name.c_str();
                        cmdItr->DelayTime = 0;
                    }
                }
                else if(StringConvert::Compare(key, "Recv", true))
                {
                    if(cmdItr != collection.End())
                    {
                        data.Clear();
                        DevCommand::FromAscii(subItr->Value.c_str(), data);
                        cmdItr->rCmd.Append(data);
                    }
                }
                else if(StringConvert::Compare(key, "DelayTime", true))
                {
                    if(cmdItr != collection.End())
                    {
                        cmdItr->DelayTime = ArgConvert::FromString<uint>(subItr->Value);
                    }
                }
            }
        }
        return true;
    }
    /**
     * @brief 将指令数据保存到文件中
     * @date 2017-11-06 10:50
     * 
     * @param [in] path 需要保存的文件路径
     * @param [in] collection 需要保存的指令数据
     */
    static bool Save(const char* path, const CachedCmdCollection& collection)
    {
        ofstream fout;
        fout.open(path, ios::out);
        if(fout.fail())
            return false;

        CachedCmdCollection::EnumeratorType enumer = collection.GetEnumerator();
        ByteBuilder buff(32);
        while(enumer.MoveNext())
        {
            fout << "[";
            enumer.Current().Name.GetString();
            fout << "]" << endl;

            fout << "Send=\"";
            buff.Clear();
            ByteConvert::ToAscii(enumer.Current().sCmd, buff);
            fout << buff.GetString() << "\"" << endl;

            fout << "Recv=\"";
            buff.Clear();
            ByteConvert::ToAscii(enumer.Current().rCmd, buff);
            fout << buff.GetString() << "\"" << endl;

            fout << "DelayTime=\"" << enumer.Current().DelayTime << "\"" << endl;
            fout << endl;
        }
        return true;
    }
protected:
    CachedCmdCollection _collection;
    CachedCmdCollection::Iterator _itr;
public:
    FileVirtualDevice()
    {
        _itr = _collection.Begin();
    }

    virtual bool Open(const char* pArg = NULL)
    {
        LOG_FUNC_NAME();
        LOGGER(_log << "Path:<" << _strput(pArg) << ">\n");
        string path = "";
        ArgParser parser;
        StringArguments arg;
        if(parser.Parse(pArg, arg))
        {
            path = arg[FileHandlerFactory::PathKey].To<string>();
        }
        else
        {
            path = _strput(pArg);
        }
        LOGGER(_log << "LoadPath:<" << path << ">\n");
        bool bOK = Load(path.c_str(), _collection);
        LOGGER(_log << "Collection Count:<" << _collection.Count() << ">\n");
        _itr = _collection.Begin();
        return _logRetValue(bOK);
    }
    virtual bool IsOpen() { return _collection.Count() > 0; }
    virtual void Close() {}

    virtual bool Write(const ByteArray& data)
    {
        LOG_FUNC_NAME();
        LOGGER(_log.WriteLine("Send:").WriteLine(data));
        _itr = _collection.Get(data);
        return _logRetValue(!(_collection.IsEof(_itr)));
    }
    virtual bool Read(ByteBuilder& data)
    {
        LOG_FUNC_NAME();
        if(_collection.IsEof(_itr))
            return _logRetValue(false);
        LOGGER(_log << "DelayTime:<" << _itr->DelayTime << ">\n");
        LOGGER(_log.WriteLine("Recv:").WriteLine(_itr->rCmd));
        if(_itr->DelayTime > 0)
        {
            Timer::Wait(_itr->DelayTime);
        }
        data.Append(_itr->rCmd);
        return _logRetValue(true);
    }
};
//--------------------------------------------------------- 
} // namespace ability 
} // namespace extension 
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_FILEVIRTUALDEVICE_H_
//========================================================= 